package com.joinway.framework.utils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.reflections.ReflectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class DataUtils {

	private final static Logger log = LoggerFactory.getLogger(DataUtils.class);
	
	private final static String[] DATE_PATTERN = new String[]{
		"yyyy-MM-dd HH:mm:ss"
		, "yyyy-MM-dd HH:mm:ss,SSS"
		, "yyyy/MM/dd HH:mm:ss"
		, "yyyyMMddHHmmss"
		, "yyyyMMdd HHmmss"
		, "yyyy/MM/dd"
		, "yyyy-MM-dd"
		, "yyyyMMdd"
	};
	
	public static int getSize(Map<?, ?> map){
		return map == null ? 0 : map.size();
	}
	
	public static int getSize(Collection<?> c){
		return c == null ? 0 : c.size();
	}

	public static int convertToInt(Object obj){
		int value = 0;
		
		try{
			value = Integer.valueOf(String.valueOf(obj));
		}catch(NumberFormatException  e){
			log.warn(e.getMessage());
		}
		
		return value;
	}
	
	public static boolean convertBool(Object obj){
		boolean ret = false;
		
		if(obj instanceof Boolean){
			ret = (Boolean)obj;
		}else if(obj instanceof Number){
			ret = Math.abs(((Number)obj).doubleValue()) > 0 ? true : false;
		}else{
			String value = String.valueOf(obj);
			value = "Y".equalsIgnoreCase(value) || "on".equalsIgnoreCase(value) || "checked".equalsIgnoreCase(value)? "true" : value;
			ret = Boolean.parseBoolean(value);
		}
		
		return ret;
	}

	public static String convertToString(Object obj){
		String value = "";
		
		if(obj != null){
			value = StringUtils.trimToEmpty(obj.toString());
		}
			
		return value;
	}
	
	public static Date convertToDate(Object obj, String...patterns) {
		Date date = null;
		
		try{
			date = DateUtils.parseDate(convertToString(obj), ArrayUtils.isEmpty(patterns) ? DATE_PATTERN : patterns);
		}catch(Exception e){
			log.warn("failed to convert {} to date", obj);
		}
		
		return date;
	}
	
	@Deprecated
	public static String plainToString(Collection<?> c, String field) throws Exception {
		return plainToString(c, field, ",");
	}
	
	@Deprecated
	public static String plainToString(Collection<?> c, String field, String separator) throws Exception {
		String plain = "";
		
		if(CollectionUtils.isNotEmpty(c)){
			for(Object o : c){
				Object e = PropertyUtils.getProperty(o, field);
				plain += convertToString(e) + separator;
			}
			
			plain = plain.substring(0, plain.length() - 1);
		}
		
		return plain;
	}
	
	@Deprecated
	public static boolean isJsonData(String text){
		String value = StringUtils.trimToEmpty(text).replaceAll("\\s+", "");
		return value.startsWith("{") && value.endsWith("}") || value.startsWith("[{") && value.endsWith("}]");
	}
	
	@SuppressWarnings("unchecked")
	public static void addAllIgnoreEmpty(Collection<?> target, Collection<?> source){
		if(CollectionUtils.isNotEmpty(source)){
			((Collection<Object>)target).addAll(source);
		}
	}
	
	public static String convertGetTextToUtf8(String text) throws Exception {
		return new String(text.getBytes("ISO-8859-1"), "UTF-8");
	}

	public static List<Field> getValidFields(Class<?> type){
		List<Field> validFields = new LinkedList<>();
		
		@SuppressWarnings("unchecked")
		Set<Field> fields = ReflectionUtils.getAllFields(type);
		
		if(getSize(fields) > 0){
			for(Field field : fields){
				int modifiers = field.getModifiers();
				if(!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) && !Modifier.isFinal(modifiers)){
					validFields.add(field);
				}
			}
		}
		
		return validFields;
	}
	
    /**
     * Filter the specified message string for characters that are sensitive
     * in HTML.  This avoids potential attacks caused by including JavaScript
     * codes in the request URL that is often reported in error messages.
     *
     * @param message The message string to be filtered
     */
	public static String filterHtml(String message){
		
        if (message == null)
            return (null);

        char content[] = new char[message.length()];
        message.getChars(0, message.length(), content, 0);
        StringBuilder result = new StringBuilder(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
            case '<':
                result.append("&lt;");
                break;
            case '>':
                result.append("&gt;");
                break;
            case '&':
                result.append("&amp;");
                break;
            case '"':
                result.append("&quot;");
                break;
            default:
                result.append(content[i]);
            }
        }
        return (result.toString());

	}
	
	public static<T extends Cloneable> List<T> clone(List<T> list){
		List<T> objects = new ArrayList<>();
		
		if(CollectionUtils.isNotEmpty(list)){
			for(T t : list){
				objects.add(ObjectUtils.clone(t));
			}
		}
		
		return objects;
	}
	
	/**
	 * 获得数组中第一个不是空字符串的值
	 * @param values
	 * @return
	 */
	public static String getNonEmptyValue(String...values){
		String value = "";
		
		if(values != null){
			for(String v : values){
				if(StringUtils.isNotEmpty(v)){
					value = v;
					break;
				}
			}
		}
		
		return value;
	}
	
	private DataUtils(){}
}
